package com.mindskip.xzs.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mindskip.xzs.context.WebContext;
import com.mindskip.xzs.domain.dto.admin.question.QuestionDTO;
import com.mindskip.xzs.domain.dto.admin.question.QuestionItemDTO;
import com.mindskip.xzs.domain.dto.QuestionObject;
import com.mindskip.xzs.domain.dto.admin.question.QuestionPageDTO;
import com.mindskip.xzs.domain.entity.Question;
import com.mindskip.xzs.domain.entity.TextContent;
import com.mindskip.xzs.domain.enums.QuestionStatusEnum;
import com.mindskip.xzs.domain.enums.QuestionTypeEnum;
import com.mindskip.xzs.domain.vo.admin.question.QuestionItemVO;
import com.mindskip.xzs.domain.vo.admin.question.QuestionPageVO;
import com.mindskip.xzs.domain.vo.admin.question.QuestionSelectVO;
import com.mindskip.xzs.exception.ParameterValidException;
import com.mindskip.xzs.repository.BaseMapper;
import com.mindskip.xzs.repository.QuestionMapper;
import com.mindskip.xzs.service.QuestionService;
import com.mindskip.xzs.service.TextContentService;
import com.mindskip.xzs.utility.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class QuestionServiceImpl extends BaseServiceImpl<Question> implements QuestionService {

    private final QuestionMapper questionMapper;

    private final TextContentService textContentService;

    protected final WebContext webContext;

    public QuestionServiceImpl(BaseMapper<Question> baseMapper, QuestionMapper questionMapper, TextContentService textContentService, WebContext webContext) {
        super(baseMapper);
        this.questionMapper = questionMapper;
        this.textContentService = textContentService;
        this.webContext = webContext;
    }

    // 得到所有题目总数
    @Override
    public Integer selectAllCount() {
        return questionMapper.selectAllCount();
    }

    @Override
    public PageInfo<QuestionPageVO> getQuestionByPage(QuestionPageDTO questionPageDTO) {

        PageHelper.startPage(questionPageDTO.getPageIndex(), questionPageDTO.getPageSize(), "id desc");
        List<Question> questionList = questionMapper.selectByPage(questionPageDTO);
        PageInfo<Question> oldPageInfo = new PageInfo<>(questionList);

        List<QuestionPageVO> questionPageVOList = questionList
                .stream()
                .map(new Function<Question, QuestionPageVO>() {
                    @Override
                    public QuestionPageVO apply(Question question) {
                        QuestionPageVO questionPageVO = BeanCopyUtils.copyBean(question, QuestionPageVO.class);
                        // 将Date类型的createTime属性转换为String类型
                        questionPageVO.setCreateTime(DateTimeUtil.dateFormat(question.getCreateTime()));
                        // 将Integer类型的score属性转换为String类型
                        questionPageVO.setScore(ExamUtil.scoreToString(question.getScore()));

                        // 从文本表t_text_content中查询每个题目所对应的文本内容
                        TextContent textContent = textContentService.selectById(question.getInfoTextContentId());
                        // 将Json字符串转换为对象
                        QuestionObject questionObject = JsonUtil.toJsonObject(textContent.getContent(), QuestionObject.class);
                        Assert.notNull(questionObject,"questionObject == null");
                        // 将字符串中可能出现的 HTML 标签清理掉
                        String clearHtml = HtmlUtil.clear(questionObject.getTitleContent());
                        questionPageVO.setShortTitle(clearHtml);
                        return questionPageVO;
                    }
                })
                .collect(Collectors.toList());
        return PageInfoUtil.copyMap(oldPageInfo, questionPageVOList);
    }

    @Override
    public List<Question> selectByIds(List<Integer> ids) {
        return questionMapper.selectByIds(ids);
    }

    @Override
    public QuestionSelectVO questionToQuestionSelectVO(Integer id) {

        Question question = questionMapper.selectByPrimaryKey(id);

        // 将Question变为QuestionSelectVO
        return this.questionToQuestionSelectVO(question);
    }

    // 将Question变为QuestionSelectVO
    public QuestionSelectVO questionToQuestionSelectVO(Question question) {

        QuestionSelectVO questionSelectVO = BeanCopyUtils.copyBean(question, QuestionSelectVO.class);

        // 将 questionSelectVO 中的 String 类型的 score 属性赋值
        questionSelectVO.setScore(ExamUtil.scoreToString(question.getScore()));

        // 从 t_text_content 表中获得题目所对应的文本内容 TextContent
        TextContent textContent = textContentService.selectById(question.getInfoTextContentId());

        // 将该 TextContent 中的 content 属性 转为 QuestionObject 对象
        QuestionObject questionObject = JsonUtil.toJsonObject(textContent.getContent(), QuestionObject.class);

        if (questionObject == null) {
            throw new RuntimeException("题目所对应的内容丢失");
        }
        // 将 questionSelectVO 中的 title、items、analyze 属性分别赋值
        questionSelectVO.setTitle(questionObject.getTitleContent());
        questionSelectVO.setItems(questionObject.getQuestionItemObjects());
        questionSelectVO.setAnalyze(questionObject.getAnalyze());

        // 将 questionSelectVO 中的 correctArray 属性赋值
        QuestionTypeEnum questionTypeEnum = QuestionTypeEnum.fromCode(question.getQuestionType());
        switch (questionTypeEnum) {
            case MultipleChoice:
                // 如果题目是多选题，则给 questionSelectVO 中的 correctArray 属性赋值
                questionSelectVO.setCorrectArray(ExamUtil.contentToArray(question.getCorrect()));
                break;
            case GapFilling:
                // 如果题目是填空题，则给 questionSelectVO 中的 correctArray 属性赋值
                List<String> correctContent = questionObject.getQuestionItemObjects()
                        .stream()
                        .map(QuestionItemVO::getContent)
                        .collect(Collectors.toList());
                questionSelectVO.setCorrectArray(correctContent);
                break;
            default:
                break;
        }

        return questionSelectVO;
    }

    @Override
    @Transactional
    public void insertOrUpdateQuestion(QuestionDTO questionDTO) {

        int qType = questionDTO.getQuestionType();
        boolean requireCorrect = qType == QuestionTypeEnum.SingleChoice.getCode() || qType == QuestionTypeEnum.TrueFalse.getCode();
        if (requireCorrect) {
            // 如果是单选题或者判断题
            if (StringUtils.isBlank(questionDTO.getCorrect())) {
                String errorMsg = ErrorUtil.parameterErrorFormat("correct", "不能为空");
                throw new ParameterValidException(errorMsg);
            }
        }

        if (qType == QuestionTypeEnum.GapFilling.getCode()) {
            // 如果是填空题
            Integer fillSumScore = questionDTO.getItems()
                    .stream()
                    .mapToInt(d -> ExamUtil.scoreToInteger(d.getScore()))
                    .sum();
            Integer questionScore = ExamUtil.scoreToInteger(questionDTO.getScore());
            if (!fillSumScore.equals(questionScore)) {
                String errorMsg = ErrorUtil.parameterErrorFormat("score", "填空分数和与题目总分不相等");
                throw new ParameterValidException(errorMsg);
            }
        }

        if (questionDTO.getId() == null) {
            insert(questionDTO, webContext.getCurrentUser().getId());
        }else {
            update(questionDTO);
        }
    }


    public void update(QuestionDTO questionDTO) {

        Question question = questionMapper.selectByPrimaryKey(questionDTO.getId());
        question.setSubjectId(questionDTO.getSubjectId());
        question.setScore(ExamUtil.scoreToInteger(questionDTO.getScore()));
        question.setGradeLevel(questionDTO.getGradeLevel());
        question.setDifficult(questionDTO.getDifficult());
        question.setCorrectFromVM(questionDTO.getCorrect(), questionDTO.getCorrectArray());

        int ret2 = questionMapper.updateByPrimaryKeySelective(question);
        if (ret2 <= 0) {
            throw new RuntimeException("插入题目失败");
        }


        // 得到 question 所对应的 infoTextContentId 属性
        Integer textContentId = question.getInfoTextContentId();

        // 从数据库中查询该 question 所对应的文本内容 TextContent
        TextContent textContent = textContentService.selectById(textContentId);

        // 给 textContent 的 content 属性赋值
        setQuestionTextContent(textContent, questionDTO);
        // 将该 question 所对应的 TextContent 对象存入到数据库
        int ret = textContentService.updateByIdFilter(textContent);
        if (ret <= 0) {
            throw new RuntimeException("更新题目所对应的文本内容失败");
        }

    }

    public void insert(QuestionDTO questionDTO, Integer userId) {

        Question question = BeanCopyUtils.copyBean(questionDTO, Question.class);

        question.setCorrectFromVM(questionDTO.getCorrect(), questionDTO.getCorrectArray());
        // 将 question 中的 String 类型 score 属性转换为 Integer
        question.setScore(ExamUtil.scoreToInteger(questionDTO.getScore()));

        TextContent textContent = new TextContent();
        // 给 textContent 的 createTime 属性赋值
        textContent.setCreateTime(new Date());
        // 给 textContent 的 content 属性赋值
        setQuestionTextContent(textContent, questionDTO);
        // 将该 question 所对应的 TextContent 对象存入到数据库
        int ret = textContentService.insertByFilter(textContent);
        if (ret <= 0) {
            throw new RuntimeException("插入题目所对应的文本内容失败");
        }

        question.setInfoTextContentId(textContent.getId());
        question.setCreateUser(userId);
        question.setStatus(QuestionStatusEnum.OK.getCode());
        question.setCreateTime(new Date());
        question.setDeleted(false);

        int ret2 = questionMapper.insertSelective(question);
        if (ret2 <= 0) {
            throw new RuntimeException("插入题目失败");
        }
    }

    public void setQuestionTextContent(TextContent textContent, QuestionDTO questionDTO){

        QuestionObject questionObject = new QuestionObject();
        // 给 questionObject 的 titleContent、analyze、correct 属性赋值
        questionObject.setTitleContent(questionDTO.getTitle());
        questionObject.setAnalyze(questionDTO.getAnalyze());
        questionObject.setCorrect(questionDTO.getCorrect());

        // 给 questionObject 的 questionItemObjects 属性赋值
        List<QuestionItemDTO> items = questionDTO.getItems();
        List<QuestionItemVO> questionItemVOList = items
                .stream()
                .map(new Function<QuestionItemDTO, QuestionItemVO>() {
                    @Override
                    public QuestionItemVO apply(QuestionItemDTO questionItemDTO) {
                        QuestionItemVO questionItemVO = new QuestionItemVO();
                        questionItemVO.setPrefix(questionItemDTO.getPrefix());
                        questionItemVO.setContent(questionItemDTO.getContent());
                        questionItemVO.setScore(questionItemDTO.getScore());
                        questionItemVO.setItemUuid(questionItemDTO.getItemUuid());
                        return questionItemVO;
                    }
                })
                .collect(Collectors.toList());
        questionObject.setQuestionItemObjects(questionItemVOList);

        // 将 questionObject 转换为 Json 字符串，赋值给 textContent 中的 content 属性
        String content = JsonUtil.toJsonStr(questionObject);
        textContent.setContent(content);
    }

    @Override
    public void softDeleted(Integer id) {

        Question question = questionMapper.selectByPrimaryKey(id);

        if (question == null) {
            throw new RuntimeException("无法查询到数据");
        }
        question.setDeleted(true);
        questionMapper.updateByPrimaryKeySelective(question);
    }
}
